import tkinter as tk
from tkinter import ttk, messagebox, font
import random
from gen import generate_data
from alg import Solution
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib

# 配置matplotlib支持中文字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'KaiTi', 'FangSong', 'SimSun']
matplotlib.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

class MinimumCostUI:
    def __init__(self, root):
        self.root = root
        self.root.title("矩形切割最小成本计算器")
        self.root.geometry("800x600")
        self.root.resizable(True, True)
        
        # 创建默认字体
        self.default_font = font.nametofont("TkDefaultFont")
        self.default_font.configure(size=12)
        self.root.option_add("*Font", self.default_font)
        
        # 设置文本和标题字体
        self.text_font = font.Font(family="SimHei", size=12)
        self.title_font = font.Font(family="SimHei", size=14, weight="bold")
        
        # 配置ttk样式
        self.style = ttk.Style()
        self.style.configure("TLabel", font=self.text_font)
        self.style.configure("TButton", font=self.text_font)
        self.style.configure("TRadiobutton", font=self.text_font)
        self.style.configure("TEntry", font=self.text_font)
        self.style.configure("TSpinbox", font=self.text_font)
        self.style.configure("TLabelframe.Label", font=self.title_font)
        
        # 存储最近一次计算的数据，用于可视化
        self.last_calculation = None
        
        self.create_widgets()
        
    def create_widgets(self):
        # 创建主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 输入参数区域
        input_frame = ttk.LabelFrame(main_frame, text="输入参数", padding="10")
        input_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 矩形尺寸
        size_frame = ttk.Frame(input_frame)
        size_frame.pack(fill=tk.X, pady=5)
        
        ttk.Label(size_frame, text="行数 (m):").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.m_var = tk.IntVar(value=3)
        ttk.Spinbox(size_frame, from_=2, to=10, textvariable=self.m_var, width=5).grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Label(size_frame, text="列数 (n):").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
        self.n_var = tk.IntVar(value=2)
        ttk.Spinbox(size_frame, from_=2, to=10, textvariable=self.n_var, width=5).grid(row=0, column=3, padx=5, pady=5)
        
        ttk.Label(size_frame, text="最大成本:").grid(row=0, column=4, padx=5, pady=5, sticky=tk.W)
        self.max_cost_var = tk.IntVar(value=10)
        ttk.Spinbox(size_frame, from_=1, to=100, textvariable=self.max_cost_var, width=5).grid(row=0, column=5, padx=5, pady=5)
        
        # 选择输入方式
        self.input_method = tk.StringVar(value="auto")
        ttk.Radiobutton(input_frame, text="自动生成切割成本", variable=self.input_method, value="auto", 
                       command=self.toggle_input_method).pack(anchor=tk.W, padx=5, pady=2)
        ttk.Radiobutton(input_frame, text="手动输入切割成本", variable=self.input_method, value="manual", 
                       command=self.toggle_input_method).pack(anchor=tk.W, padx=5, pady=2)
        
        # 手动输入区域
        self.manual_input_frame = ttk.Frame(input_frame)
        self.manual_input_frame.pack(fill=tk.X, padx=5, pady=5)
        self.manual_input_frame.pack_forget()  # 默认隐藏
        
        ttk.Label(self.manual_input_frame, text="横向切割成本 (用逗号分隔):").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.h_cut_var = tk.StringVar()
        ttk.Entry(self.manual_input_frame, textvariable=self.h_cut_var, width=30).grid(row=0, column=1, padx=5, pady=5)
        
        ttk.Label(self.manual_input_frame, text="纵向切割成本 (用逗号分隔):").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.v_cut_var = tk.StringVar()
        ttk.Entry(self.manual_input_frame, textvariable=self.v_cut_var, width=30).grid(row=1, column=1, padx=5, pady=5)
        
        # 操作按钮
        btn_frame = ttk.Frame(main_frame)
        btn_frame.pack(fill=tk.X, padx=5, pady=5)
        
        ttk.Button(btn_frame, text="计算最小成本", command=self.calculate).pack(side=tk.LEFT, padx=5, pady=5)
        ttk.Button(btn_frame, text="可视化切割", command=self.show_visualization).pack(side=tk.LEFT, padx=5, pady=5)
        ttk.Button(btn_frame, text="重置", command=self.reset).pack(side=tk.LEFT, padx=5, pady=5)
        

        result_frame = ttk.LabelFrame(main_frame, text="计算结果", padding="10")
        result_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        

        self.result_text = tk.Text(result_frame, height=10, width=50, font=self.text_font)
        self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        scrollbar = ttk.Scrollbar(result_frame, orient="vertical", command=self.result_text.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.result_text.configure(yscrollcommand=scrollbar.set)
        

        
    def toggle_input_method(self):
        if self.input_method.get() == "manual":
            self.manual_input_frame.pack(fill=tk.X, padx=5, pady=5)
            # 预填充输入框
            m, n = self.m_var.get(), self.n_var.get()
            self.h_cut_var.set(",".join(str(random.randint(1, self.max_cost_var.get())) for _ in range(m-1)))
            self.v_cut_var.set(",".join(str(random.randint(1, self.max_cost_var.get())) for _ in range(n-1)))
        else:
            self.manual_input_frame.pack_forget()
            
    def parse_input_list(self, input_str):
        try:
            return [int(x.strip()) for x in input_str.split(",") if x.strip()]
        except ValueError:
            messagebox.showerror("输入错误", "请输入有效的数字，用逗号分隔")
            return None
            
    def calculate(self):
        m = self.m_var.get()
        n = self.n_var.get()
        
        if self.input_method.get() == "auto":
            max_cost = self.max_cost_var.get()
            _, _, hcut, vcut = generate_data(m, n, max_cost)
        else:
            hcut = self.parse_input_list(self.h_cut_var.get())
            vcut = self.parse_input_list(self.v_cut_var.get())
            
            if hcut is None or vcut is None:
                return
                
            if len(hcut) != m-1:
                messagebox.showerror("输入错误", f"横向切割成本应有 {m-1} 个值")
                return
                
            if len(vcut) != n-1:
                messagebox.showerror("输入错误", f"纵向切割成本应有 {n-1} 个值")
                return
        
        solver = Solution()
        result = solver.minimumCost(m, n, hcut, vcut)
        
        # 存储当前计算结果，用于可视化
        self.last_calculation = {
            'm': m,
            'n': n,
            'hcut': hcut,
            'vcut': vcut,
            'result': result
        }
        
        # 显示结果
        self.result_text.delete(1.0, tk.END)
        self.result_text.insert(tk.END, f"矩形尺寸: {m} × {n}\n")
        self.result_text.insert(tk.END, f"横向切割成本: {hcut}\n")
        self.result_text.insert(tk.END, f"纵向切割成本: {vcut}\n")
        self.result_text.insert(tk.END, f"最小总成本: {result}\n")
        
        # 不再自动可视化
        # self.visualize_cutting(m, n, hcut, vcut)
    
    def show_visualization(self):
        """处理可视化按钮点击事件 - 在新窗口中显示可视化"""
        if self.last_calculation is None:
            messagebox.showinfo("提示", "请先计算最小成本再进行可视化")
            return
            
        m = self.last_calculation['m']
        n = self.last_calculation['n']
        hcut = self.last_calculation['hcut']
        vcut = self.last_calculation['vcut']
        
        # 创建新窗口
        vis_window = tk.Toplevel(self.root)
        vis_window.title("切割可视化")
        vis_window.geometry("700x600")
        
        # 在新窗口中创建matplotlib图形
        fig, ax = plt.subplots(figsize=(8, 7), dpi=100)
        canvas = FigureCanvasTkAgg(fig, master=vis_window)
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 在新窗口中添加关闭按钮
        btn_frame = ttk.Frame(vis_window)
        btn_frame.pack(fill=tk.X, padx=10, pady=10)
        ttk.Button(btn_frame, text="关闭", command=vis_window.destroy).pack(side=tk.RIGHT)
        
        # 可视化切割
        self.visualize_cutting(m, n, hcut, vcut, fig, ax, canvas)
        
    def visualize_cutting(self, m, n, hcut, vcut, fig=None, ax=None, canvas=None):
        """在指定的图形上可视化切割过程"""
        # 如果没有提供图形对象，则使用已有的或创建新的
        if ax is None:
            if hasattr(self, 'ax'):
                ax = self.ax
            else:
                _, ax = plt.subplots()
        
        ax.clear()
        
        # 设置更大的字体大小
        plt.rcParams.update({'font.size': 14})
        
        # 绘制初始矩形
        ax.add_patch(plt.Rectangle((0, 0), n, m, fill=False, edgecolor='black'))
        
        # 计算切割顺序
        cuts = [(c, 0, i+1) for i, c in enumerate(hcut)] + [(c, 1, i+1) for i, c in enumerate(vcut)]
        cuts.sort(reverse=True)  # 按成本从高到低排序
        
        # 横向和纵向线的坐标
        h_lines = []  # 形式为 (y坐标, 成本, 顺序)
        v_lines = []  # 形式为 (x坐标, 成本, 顺序)
        
        # 根据切割顺序绘制线条
        for i, (cost, t, idx) in enumerate(cuts):
            color = plt.cm.viridis(i / len(cuts))  # 颜色从浅到深
            if t == 0:  # 横向切割
                y = idx / (len(hcut) + 1) * m
                h_lines.append((y, cost, i+1))
                ax.axhline(y=y, color=color, linestyle='-', linewidth=2)
            else:  # 纵向切割
                x = idx / (len(vcut) + 1) * n
                v_lines.append((x, cost, i+1))
                ax.axvline(x=x, color=color, linestyle='-', linewidth=2)
        
        # 添加标签，增大字体
        for y, cost, order in h_lines:
            ax.text(-0.2, y, f"{cost}", va='center', ha='right', fontsize=12)
            ax.text(n/2, y, f"#{order}", va='center', ha='center', 
                    bbox=dict(facecolor='white', alpha=0.7), fontsize=12)
            
        for x, cost, order in v_lines:
            ax.text(x, -0.2, f"{cost}", va='top', ha='center', fontsize=12)
            ax.text(x, m/2, f"#{order}", va='center', ha='center', 
                    bbox=dict(facecolor='white', alpha=0.7), fontsize=12)
        
        ax.set_xlim(-0.5, n+0.5)
        ax.set_ylim(-0.5, m+0.5)
        ax.set_aspect('equal')
        ax.set_title("切割顺序和成本可视化", fontsize=16)
        
        # 更新画布
        if canvas:
            canvas.draw()
        
    def reset(self):
        self.m_var.set(3)
        self.n_var.set(2)
        self.max_cost_var.set(10)
        self.input_method.set("auto")
        self.h_cut_var.set("")
        self.v_cut_var.set("")
        self.manual_input_frame.pack_forget()
        self.result_text.delete(1.0, tk.END)
        if hasattr(self, 'ax'):
            self.ax.clear()
            if hasattr(self, 'canvas'):
                self.canvas.draw()
        self.last_calculation = None

if __name__ == "__main__":
    root = tk.Tk()
    app = MinimumCostUI(root)
    root.mainloop()
